﻿using System;
using System.Collections.Generic;
using System.Text;
using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.GZip;
using System.IO;

public class ZipFile
{
    List<string> files = new List<string>();
    List<string> paths = new List<string>();


    /// <summary>   
    /// Compressed directory (including all files and subdirectories),
    /// </summary>   
    /// <param name="rootPath">To compress the root directory</param>   
    /// <param name="destinationPath">Save the path</param>   
    /// <param name="compressLevel">0 - store only to 9 - means best compression</param>   
    public void ZipFileFromDirectory(string rootPath, string destinationPath, int compressLevel)
    {
        GetAllDirectories(rootPath);

        string rootMark = rootPath;//Get the current position of the path, when the compression will compress contents into the relative path.
        Crc32 crc = new Crc32();
        ZipOutputStream outPutStream = new ZipOutputStream(File.Create(destinationPath));
        outPutStream.SetLevel(compressLevel); // 0 - store only to 9 - means best compression

        foreach (string file in files)
        {
            FileStream fileStream = File.OpenRead(file);//Open compressed files

            byte[] buffer = new byte[fileStream.Length];
            fileStream.Read(buffer, 0, buffer.Length);
            ZipEntry entry = new ZipEntry(file.Replace(rootMark, string.Empty));
            entry.DateTime = DateTime.Now;
            entry.Size = fileStream.Length;
            fileStream.Close();
            crc.Reset();
            crc.Update(buffer);
            entry.Crc = crc.Value;
            outPutStream.PutNextEntry(entry);
            outPutStream.Write(buffer, 0, buffer.Length);
        }

        this.files.Clear();

        foreach (string emptyPath in paths)
        {
            ZipEntry entry = new ZipEntry(emptyPath.Replace(rootMark, string.Empty) + "/");
            outPutStream.PutNextEntry(entry);
        }

        this.paths.Clear();
        outPutStream.Finish();
        outPutStream.Close();
    }

    /// <summary>   
    /// Get all files and folders ,Separately in files and paths
    /// </summary>   
    /// <param name="rootPath">Root directory</param>   
    private void GetAllDirectories(string rootPath)
    {
        string[] subPaths = Directory.GetDirectories(rootPath);//Get all subdirectories

        foreach (string path in subPaths)
        {
            GetAllDirectories(path);//For each word List do the same with the root directory: find subdirectories operation and the current directory name in "List"
        }
        string[] files = Directory.GetFiles(rootPath);
        foreach (string file in files)
        {
            this.files.Add(file);//Save all files full name and path in "List" of current directory
        }
        if (subPaths.Length == files.Length && files.Length == 0)//If is empty directory
        {
            this.paths.Add(rootPath);//Save empty directory
        }
    }
}